﻿using Abp.Authorization.Users;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Events.Bus.Entities;
using Abp.Events.Bus.Handlers;
using Abp.Runtime.Caching;
using Mt.Organizations;
using Mt.Site.Core.Base.Authorization.Users;
using Mt.Site.Core.Organizations.Posts;
using System.Linq;

namespace Mt.Site.Core.WorkFlows.Common.Cache
{
    public class UserInfoCacheItemInvalidator :
        IEventHandler<EntityChangedEventData<User>>,
        IEventHandler<EntityChangedEventData<UserOrganizationUnit>>,
        IEventHandler<EntityChangedEventData<UserPost>>,
        IEventHandler<EntityChangedEventData<PostOrganization>>,
        IEventHandler<EntityChangedEventData<MtOrganizationUnit>>,
        IEventHandler<EntityChangedEventData<Post>>,
        ITransientDependency
    {
        private readonly ICacheManager _cacheManager;

        private readonly IRepository<UserOrganizationUnit, long> _userOrganizationUnitRepository;
        private readonly IRepository<UserPost, long> _userPostRepository;

        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public UserInfoCacheItemInvalidator(
            ICacheManager cacheManager,
            IUnitOfWorkManager unitOfWorkManager,
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
            IRepository<UserPost, long> userPostRepository)
        {
            _cacheManager = cacheManager;

            _userOrganizationUnitRepository = userOrganizationUnitRepository;
            _userPostRepository = userPostRepository;

            _unitOfWorkManager = unitOfWorkManager;
        }

        public void HandleEvent(EntityChangedEventData<User> eventData)
        {
            var cacheKey = eventData.Entity.Id + "@" + eventData.Entity.TenantId;

            _cacheManager.GetUserInfoCache().Remove(cacheKey);

            var allCacheKey = _cacheManager.GetCommonCacheKey(eventData.Entity.TenantId);
            _cacheManager.GetAllUsersCache().Remove(allCacheKey);
            _cacheManager.GetAllUserOrganinzedCache().Remove(allCacheKey);
        }

        public void HandleEvent(EntityChangedEventData<UserOrganizationUnit> eventData)
        {
            var cacheKey = eventData.Entity.UserId + "@" + eventData.Entity.TenantId;
            _cacheManager.GetUserInfoCache().Remove(cacheKey);

            var allCacheKey = _cacheManager.GetCommonCacheKey(eventData.Entity.TenantId);
            _cacheManager.GetAllUsersCache().Remove(allCacheKey);
            _cacheManager.GetAllUserOrganinzedCache().Remove(allCacheKey);
        }

        public void HandleEvent(EntityChangedEventData<UserPost> eventData)
        {
            var cacheKey = eventData.Entity.UserId + "@" + eventData.Entity.TenantId;
            _cacheManager.GetUserInfoCache().Remove(cacheKey);

            var allCacheKey = _cacheManager.GetCommonCacheKey(eventData.Entity.TenantId);
            _cacheManager.GetAllUsersCache().Remove(allCacheKey);
            _cacheManager.GetAllUserOrganinzedCache().Remove(allCacheKey);
        }

        public void HandleEvent(EntityChangedEventData<PostOrganization> eventData)
        {
            var postId = eventData.Entity.PostId;
            var tenantId = eventData.Entity.TenantId;

            var userIdList = _unitOfWorkManager.WithUnitOfWork(() => {
                return _userPostRepository.GetAllList(c => c.PostId == postId).Select(c => c.UserId);
            });

            var cache = _cacheManager.GetUserInfoCache();
            foreach (var userId in userIdList)
            {
                var cacheKey = userId + "@" + tenantId;
                cache.Remove(cacheKey);
            }

            var allCacheKey = _cacheManager.GetCommonCacheKey(eventData.Entity.TenantId);
            _cacheManager.GetAllPostsCache().Remove(allCacheKey);
            _cacheManager.GetAllUserOrganinzedCache().Remove(allCacheKey);
        }

        public void HandleEvent(EntityChangedEventData<MtOrganizationUnit> eventData)
        {
            var unitId = eventData.Entity.Id;
            var tenantId = eventData.Entity.TenantId;

            var userIdList = _unitOfWorkManager.WithUnitOfWork(() => {
                return _userOrganizationUnitRepository.GetAllList(c => c.OrganizationUnitId == unitId).Select(c => c.UserId);
            });

            var cache = _cacheManager.GetUserInfoCache();
            foreach (var userId in userIdList)
            {
                var cacheKey = userId + "@" + (tenantId ?? 0);
                cache.Remove(cacheKey);
            }

            var allCacheKey = _cacheManager.GetCommonCacheKey(eventData.Entity.TenantId);
            _cacheManager.GetAllUnitsCache().Remove(allCacheKey);
            _cacheManager.GetAllPostsCache().Remove(allCacheKey);
            _cacheManager.GetAllUserOrganinzedCache().Remove(allCacheKey);
        }

        public void HandleEvent(EntityChangedEventData<Post> eventData)
        {
            var postId = eventData.Entity.Id;
            var tenantId = eventData.Entity.TenantId;

            var userIdList = _unitOfWorkManager.WithUnitOfWork(() => {
                return _userPostRepository.GetAllList(c => c.PostId == postId).Select(c => c.UserId);
            });

            var cache = _cacheManager.GetUserInfoCache();
            foreach (var userId in userIdList)
            {
                var cacheKey = userId + "@" + tenantId;
                cache.Remove(cacheKey);
            }

            var allCacheKey = _cacheManager.GetCommonCacheKey(eventData.Entity.TenantId);
            _cacheManager.GetAllPostsCache().Remove(allCacheKey);
            _cacheManager.GetAllUserOrganinzedCache().Remove(allCacheKey);
        }
    }
}
